/*
 * PonyView.java
 */
package at.alexanderpehm.pony;

import at.alexanderpehm.pony.model.NoteInfo;
import at.alexanderpehm.pony.controller.NoteBookDAO;
import at.alexanderpehm.pony.event.EventRegistry;
import at.alexanderpehm.pony.event.EventRegistry.EventType;
import at.alexanderpehm.pony.event.PonyEventListener;
import java.awt.Desktop;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.text.html.HTMLEditorKit;

/**
 * The application's main frame.
 */
public class PonyView extends FrameView implements PonyEventListener {

    private NoteBookDAO noteDAO = new NoteBookDAO();
    private NoteTree noteTree = new NoteTree(noteDAO.getCurrentNotebookPath());
    private NoteInfo currentlyOpenNote;
    int autoSaveDelay = 5000; //milliseconds
    private final Timer autoSaveTimer;

    //Text Formatting Actions
    javax.swing.Action boldAction = new HTMLEditorKit.BoldAction();
    javax.swing.Action italicAction = new HTMLEditorKit.ItalicAction();
    javax.swing.Action underlineAction = new HTMLEditorKit.UnderlineAction();



    public PonyView(SingleFrameApplication app) {
        super(app);
        EventRegistry.getInstance().registerListener(this);
        initComponents();

        autoSaveTimer = new Timer(autoSaveDelay, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent evt) {
                saveNote();
            }
        });
        autoSaveTimer.setRepeats(true);

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

            @Override
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String) (evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer) (evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        treeScrollPane = new javax.swing.JScrollPane();
        tree =  noteTree.getTree();
        menuBarPanel = new javax.swing.JPanel();
        addNoteButton = new javax.swing.JButton();
        saveNoteButton = new javax.swing.JButton();
        openAttachment = new javax.swing.JButton();
        btnBold = new javax.swing.JButton();
        btnItalic = new javax.swing.JButton();
        btnUnderline = new javax.swing.JButton();
        centerPane = new javax.swing.JPanel();
        editorScrollPane = new javax.swing.JScrollPane();
        editorPane = new javax.swing.JEditorPane();
        attachmentScrollPane = new javax.swing.JScrollPane();
        attachmentList = new javax.swing.JList();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        jMenuItem3 = new javax.swing.JMenuItem();
        jMenuItem2 = new javax.swing.JMenuItem();
        jMenuItem1 = new javax.swing.JMenuItem();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        formatMenu = new javax.swing.JMenu();
        boldMnuItem = new javax.swing.JMenuItem();
        italicMnuItem = new javax.swing.JMenuItem();
        underlineMnuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        statusMessageLabel = new javax.swing.JLabel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();

        mainPanel.setName("mainPanel"); // NOI18N
        mainPanel.setLayout(new java.awt.BorderLayout());

        treeScrollPane.setName("treeScrollPane"); // NOI18N
        treeScrollPane.setPreferredSize(new java.awt.Dimension(200, 384));

        tree.setName("tree"); // NOI18N
        treeScrollPane.setViewportView(tree);

        mainPanel.add(treeScrollPane, java.awt.BorderLayout.LINE_START);

        menuBarPanel.setName("menuBarPanel"); // NOI18N
        menuBarPanel.setLayout(new javax.swing.BoxLayout(menuBarPanel, javax.swing.BoxLayout.LINE_AXIS));

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(at.alexanderpehm.pony.PonyApp.class).getContext().getActionMap(PonyView.class, this);
        addNoteButton.setAction(actionMap.get("newNote")); // NOI18N
        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(at.alexanderpehm.pony.PonyApp.class).getContext().getResourceMap(PonyView.class);
        addNoteButton.setIcon(resourceMap.getIcon("addNoteButton.icon")); // NOI18N
        addNoteButton.setText(resourceMap.getString("addNoteButton.text")); // NOI18N
        addNoteButton.setName("addNoteButton"); // NOI18N
        menuBarPanel.add(addNoteButton);

        saveNoteButton.setAction(actionMap.get("saveNote")); // NOI18N
        saveNoteButton.setIcon(resourceMap.getIcon("saveNoteButton.icon")); // NOI18N
        saveNoteButton.setText(resourceMap.getString("saveNoteButton.text")); // NOI18N
        saveNoteButton.setToolTipText(resourceMap.getString("saveNoteButton.toolTipText")); // NOI18N
        saveNoteButton.setName("saveNoteButton"); // NOI18N
        menuBarPanel.add(saveNoteButton);

        openAttachment.setAction(actionMap.get("openAttachment")); // NOI18N
        openAttachment.setIcon(resourceMap.getIcon("openAttachment.icon")); // NOI18N
        openAttachment.setName("openAttachment"); // NOI18N
        menuBarPanel.add(openAttachment);

        btnBold.setAction(boldAction);
        btnBold.setFont(resourceMap.getFont("btnBold.font")); // NOI18N
        btnBold.setText(resourceMap.getString("btnBold.text")); // NOI18N
        btnBold.setToolTipText(resourceMap.getString("btnBold.toolTipText")); // NOI18N
        btnBold.setActionCommand(resourceMap.getString("btnBold.actionCommand")); // NOI18N
        btnBold.setName("btnBold"); // NOI18N
        menuBarPanel.add(btnBold);

        btnItalic.setAction(italicAction);
        btnItalic.setFont(resourceMap.getFont("btnItalic.font")); // NOI18N
        btnItalic.setText(resourceMap.getString("btnItalic.text")); // NOI18N
        btnItalic.setToolTipText(resourceMap.getString("btnItalic.toolTipText")); // NOI18N
        btnItalic.setName("btnItalic"); // NOI18N
        menuBarPanel.add(btnItalic);

        btnUnderline.setAction(underlineAction);
        btnUnderline.setFont(resourceMap.getFont("btnUnderline.font")); // NOI18N
        btnUnderline.setText(resourceMap.getString("btnUnderline.text")); // NOI18N
        btnUnderline.setToolTipText(resourceMap.getString("btnUnderline.toolTipText")); // NOI18N
        btnUnderline.setName("btnUnderline"); // NOI18N
        menuBarPanel.add(btnUnderline);

        mainPanel.add(menuBarPanel, java.awt.BorderLayout.PAGE_START);

        centerPane.setName("centerPane"); // NOI18N
        centerPane.setLayout(new java.awt.BorderLayout());

        editorScrollPane.setName("editorScrollPane"); // NOI18N

        editorPane.setEditorKit(new HTMLEditorKit());
        editorPane.setFont(resourceMap.getFont("editorPane.font")); // NOI18N
        editorPane.setName("editorPane"); // NOI18N
        editorPane.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                editorPaneKeyTyped(evt);
            }
        });
        editorScrollPane.setViewportView(editorPane);

        centerPane.add(editorScrollPane, java.awt.BorderLayout.CENTER);

        attachmentScrollPane.setName("attachmentScrollPane"); // NOI18N

        attachmentList.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        attachmentList.setName("attachmentList"); // NOI18N
        attachmentScrollPane.setViewportView(attachmentList);

        centerPane.add(attachmentScrollPane, java.awt.BorderLayout.PAGE_END);

        mainPanel.add(centerPane, java.awt.BorderLayout.CENTER);

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setAction(actionMap.get("openNotebook")); // NOI18N
        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        jMenuItem3.setAction(actionMap.get("newNotebook")); // NOI18N
        jMenuItem3.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem3.setText(resourceMap.getString("jMenuItem3.text")); // NOI18N
        jMenuItem3.setName("jMenuItem3"); // NOI18N
        fileMenu.add(jMenuItem3);

        jMenuItem2.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem2.setText(resourceMap.getString("jMenuItem2.text")); // NOI18N
        jMenuItem2.setName("jMenuItem2"); // NOI18N
        jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem2ActionPerformed(evt);
            }
        });
        fileMenu.add(jMenuItem2);

        jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem1.setText(resourceMap.getString("jMenuItem1.text")); // NOI18N
        jMenuItem1.setName("jMenuItem1"); // NOI18N
        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem1ActionPerformed(evt);
            }
        });
        fileMenu.add(jMenuItem1);

        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        formatMenu.setText(resourceMap.getString("formatMenu.text")); // NOI18N
        formatMenu.setName("formatMenu"); // NOI18N

        boldMnuItem.setAction(boldAction);
        boldMnuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_B, java.awt.event.InputEvent.CTRL_MASK));
        boldMnuItem.setText(resourceMap.getString("boldMnuItem.text")); // NOI18N
        boldMnuItem.setName("boldMnuItem"); // NOI18N
        formatMenu.add(boldMnuItem);

        italicMnuItem.setAction(italicAction);
        italicMnuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_I, java.awt.event.InputEvent.CTRL_MASK));
        italicMnuItem.setText(resourceMap.getString("italicMnuItem.text")); // NOI18N
        italicMnuItem.setName("italicMnuItem"); // NOI18N
        formatMenu.add(italicMnuItem);

        underlineMnuItem.setAction(underlineAction);
        underlineMnuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_U, java.awt.event.InputEvent.CTRL_MASK));
        underlineMnuItem.setText(resourceMap.getString("underlineMnuItem.text")); // NOI18N
        underlineMnuItem.setName("underlineMnuItem"); // NOI18N
        formatMenu.add(underlineMnuItem);

        menuBar.add(formatMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setName("statusPanel"); // NOI18N
        statusPanel.setPreferredSize(new java.awt.Dimension(463, 30));
        statusPanel.setLayout(new java.awt.GridLayout(1, 0));

        statusMessageLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusMessageLabel.setAlignmentX(5.0F);
        statusMessageLabel.setName("statusMessageLabel"); // NOI18N
        statusPanel.add(statusMessageLabel);

        statusPanelSeparator.setOrientation(javax.swing.SwingConstants.VERTICAL);
        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N
        statusPanel.add(statusPanelSeparator);

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N
        statusPanel.add(statusAnimationLabel);

        progressBar.setName("progressBar"); // NOI18N
        statusPanel.add(progressBar);

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents

    private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_jMenuItem1ActionPerformed

    private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed
        // TODO add your handling code here:
        openNotebook();
    }//GEN-LAST:event_jMenuItem2ActionPerformed

    private void editorPaneKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_editorPaneKeyTyped
        statusMessageLabel.setText("Note modified");
    }//GEN-LAST:event_editorPaneKeyTyped

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addNoteButton;
    private javax.swing.JList attachmentList;
    private javax.swing.JScrollPane attachmentScrollPane;
    private javax.swing.JMenuItem boldMnuItem;
    private javax.swing.JButton btnBold;
    private javax.swing.JButton btnItalic;
    private javax.swing.JButton btnUnderline;
    private javax.swing.JPanel centerPane;
    private javax.swing.JEditorPane editorPane;
    private javax.swing.JScrollPane editorScrollPane;
    private javax.swing.JMenu formatMenu;
    private javax.swing.JMenuItem italicMnuItem;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem2;
    private javax.swing.JMenuItem jMenuItem3;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JPanel menuBarPanel;
    private javax.swing.JButton openAttachment;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JButton saveNoteButton;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JTree tree;
    private javax.swing.JScrollPane treeScrollPane;
    private javax.swing.JMenuItem underlineMnuItem;
    // End of variables declaration//GEN-END:variables
    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;
    private JDialog aboutBox;

    @Override
    public void notify(EventType t, Object o) {
        if (t.equals(EventType.NOTE_SELECTED) && o instanceof NoteInfo) {
            NoteInfo noteInfo = (NoteInfo) o;
            editorPane.setText(noteDAO.readNote(noteInfo));
            currentlyOpenNote = noteInfo;
            attachmentList.setListData(noteDAO.getAttachments(noteInfo));
            //now that a note is selected, enable auto-save
            autoSaveTimer.start();
        }
    }

    @Action
    public void saveNote() {
        noteDAO.updateNote(currentlyOpenNote, editorPane.getText());
        statusMessageLabel.setText("Note saved");
    }

    @Action
    public void openAttachment() {
        String rootPath = noteDAO.getCurrentNotebookPath();
        String relativePath = currentlyOpenNote.getRelativePath();
        String attachmentFileName = (String) attachmentList.getSelectedValue();
        File file = new File(rootPath + relativePath + File.separator + attachmentFileName);
        try {
            Desktop.getDesktop().edit(file);
        } catch (IOException ex) {
            Logger.getLogger(PonyView.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

        @Action
    public void openNotebook() {
        JFileChooser chooser = new JFileChooser();
        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int returnVal = chooser.showOpenDialog(mainPanel);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            noteDAO.setCurrentNotebookPath(chooser.getSelectedFile().getAbsolutePath() + File.separator);
            noteTree.clearAndLoadNew();
        }
    }

    @Action
    public void newNotebook() {
        JFileChooser chooser = new JFileChooser();
        int returnVal = chooser.showSaveDialog(mainPanel);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            System.out.println("You chose to create the new Notebook: "
                    + chooser.getSelectedFile().getName());
        }
    }

    @Action
    public void newNote() {
        NoteInfo noteInfo = new NoteInfo("NewNote", null);
        noteInfo = noteDAO.createNote(noteInfo);
        noteTree.addObject(noteInfo);
    }
    
    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = PonyApp.getApplication().getMainFrame();
            aboutBox = new PonyAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        PonyApp.getApplication().show(aboutBox);
    }
}
